import OSS from 'ali-oss'
import { OSS_CONFIG, generateFileName, validateFileType, validateFileSize } from './ossConfig'

// 分片信息接口
export interface ChunkInfo {
  partNumber: number
  etag: string
  size: number
  offset: number
}

// 上传任务信息接口
export interface UploadTask {
  id: string
  fileName: string
  fileSize: number
  objectKey: string
  uploadId: string
  partSize: number
  totalParts: number
  uploadedParts: ChunkInfo[]
  completedParts: number
  progress: number
  status: 'pending' | 'uploading' | 'paused' | 'completed' | 'failed'
  startTime: number
  lastUpdateTime: number
  error?: string
}

// 断点续传配置
export interface ResumeUploadConfig {
  // 分片大小
  partSize: number
  // 并发上传数
  parallel: number
  // 重试次数
  retries: number
  // 超时时间
  timeout: number
  // 是否启用断点续传
  enableResume: boolean
  // 本地存储键前缀
  storageKeyPrefix: string
}

// 默认配置
const DEFAULT_CONFIG: ResumeUploadConfig = {
  partSize: OSS_CONFIG.partSize,
  parallel: OSS_CONFIG.parallel,
  retries: OSS_CONFIG.retries,
  timeout: OSS_CONFIG.timeout,
  enableResume: true,
  storageKeyPrefix: 'oss_upload_task_'
}

// 断点续传管理器类
export class ResumeUploadManager {
  private config: ResumeUploadConfig
  private tasks: Map<string, UploadTask> = new Map()
  private activeUploads: Map<string, AbortController> = new Map()

  constructor(config: Partial<ResumeUploadConfig> = {}) {
    this.config = { ...DEFAULT_CONFIG, ...config }
    this.loadTasksFromStorage()
  }

  // 从本地存储加载任务
  private loadTasksFromStorage(): void {
    try {
      const keys = Object.keys(localStorage).filter(key => 
        key.startsWith(this.config.storageKeyPrefix)
      )
      
      keys.forEach(key => {
        const taskData = localStorage.getItem(key)
        if (taskData) {
          try {
            const task: UploadTask = JSON.parse(taskData)
            // 只加载未完成的任务
            if (task.status !== 'completed') {
              task.status = 'paused' // 重新加载的任务设为暂停状态
              this.tasks.set(task.id, task)
            }
          } catch (error) {
            console.warn('加载上传任务失败:', key, error)
            localStorage.removeItem(key)
          }
        }
      })
    } catch (error) {
      console.error('从本地存储加载任务失败:', error)
    }
  }

  // 保存任务到本地存储
  private saveTaskToStorage(task: UploadTask): void {
    try {
      const key = `${this.config.storageKeyPrefix}${task.id}`
      localStorage.setItem(key, JSON.stringify(task))
    } catch (error) {
      console.error('保存任务到本地存储失败:', error)
    }
  }

  // 从本地存储删除任务
  private removeTaskFromStorage(taskId: string): void {
    try {
      const key = `${this.config.storageKeyPrefix}${taskId}`
      localStorage.removeItem(key)
    } catch (error) {
      console.error('从本地存储删除任务失败:', error)
    }
  }

  // 创建OSS客户端
  private createOSSClient(): OSS {
    return new OSS({
      region: OSS_CONFIG.region,
      accessKeyId: OSS_CONFIG.accessKeyId,
      accessKeySecret: OSS_CONFIG.accessKeySecret,
      bucket: OSS_CONFIG.bucket,
    })
  }

  // 计算文件分片信息
  private calculateChunks(fileSize: number, partSize: number): { totalParts: number; chunks: Array<{ partNumber: number; offset: number; size: number }> } {
    const totalParts = Math.ceil(fileSize / partSize)
    const chunks: Array<{ partNumber: number; offset: number; size: number }> = []

    for (let i = 0; i < totalParts; i++) {
      const offset = i * partSize
      const size = Math.min(partSize, fileSize - offset)
      chunks.push({
        partNumber: i + 1,
        offset,
        size
      })
    }

    return { totalParts, chunks }
  }

  // 创建上传任务
  createUploadTask(file: File, objectKey?: string): UploadTask {
    const taskId = `upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
    const fileName = objectKey || generateFileName(file.name)
    const fullObjectKey = objectKey || `${OSS_CONFIG.uploadPath}${fileName}`
    
    const { totalParts } = this.calculateChunks(file.size, this.config.partSize)
    
    const task: UploadTask = {
      id: taskId,
      fileName: file.name,
      fileSize: file.size,
      objectKey: fullObjectKey,
      uploadId: '', // 将在开始上传时获取
      partSize: this.config.partSize,
      totalParts,
      uploadedParts: [],
      completedParts: 0,
      progress: 0,
      status: 'pending',
      startTime: Date.now(),
      lastUpdateTime: Date.now()
    }

    this.tasks.set(taskId, task)
    this.saveTaskToStorage(task)
    
    return task
  }

  // 开始或恢复上传
  async startUpload(
    taskId: string, 
    file: File, 
    onProgress?: (task: UploadTask) => void
  ): Promise<{ success: boolean; url?: string; error?: string }> {
    const task = this.tasks.get(taskId)
    if (!task) {
      return { success: false, error: '任务不存在' }
    }

    try {
      // 创建中止控制器
      const abortController = new AbortController()
      this.activeUploads.set(taskId, abortController)

      // 更新任务状态
      task.status = 'uploading'
      task.startTime = Date.now()
      this.saveTaskToStorage(task)

      const client = this.createOSSClient()
      
      // 如果是新任务，初始化分片上传
      if (!task.uploadId) {
        const initResult = await client.initMultipartUpload(task.objectKey)
        task.uploadId = initResult.uploadId
        this.saveTaskToStorage(task)
      }

      // 计算需要上传的分片
      const { chunks } = this.calculateChunks(file.size, task.partSize)
      const uploadedPartNumbers = new Set(task.uploadedParts.map(p => p.partNumber))
      const pendingChunks = chunks.filter(chunk => !uploadedPartNumbers.has(chunk.partNumber))

      // 并发上传分片
      const uploadPromises = pendingChunks.map(chunk => 
        this.uploadChunk(client, task, file, chunk, abortController.signal)
      )

      // 等待所有分片上传完成
      const results = await Promise.allSettled(uploadPromises)
      
      // 检查是否有失败的分片
      const failedChunks = results.filter(result => result.status === 'rejected')
      if (failedChunks.length > 0) {
        task.status = 'failed'
        task.error = `有 ${failedChunks.length} 个分片上传失败`
        this.saveTaskToStorage(task)
        return { success: false, error: task.error }
      }

      // 完成分片上传
      const completeResult = await client.completeMultipartUpload(
        task.objectKey,
        task.uploadId,
        task.uploadedParts.map(p => ({ partNumber: p.partNumber, etag: p.etag }))
      )

      // 更新任务状态为完成
      task.status = 'completed'
      task.progress = 100
      task.lastUpdateTime = Date.now()
      this.saveTaskToStorage(task)

      // 清理本地存储
      this.removeTaskFromStorage(taskId)
      this.tasks.delete(taskId)
      this.activeUploads.delete(taskId)

      return {
        success: true,
        url: completeResult.res.requestUrls[0].split('?')[0]
      }

    } catch (error) {
      task.status = 'failed'
      task.error = error instanceof Error ? error.message : '上传失败'
      task.lastUpdateTime = Date.now()
      this.saveTaskToStorage(task)
      
      this.activeUploads.delete(taskId)
      
      return {
        success: false,
        error: task.error
      }
    }
  }

  // 上传单个分片
  private async uploadChunk(
    client: OSS,
    task: UploadTask,
    file: File,
    chunk: { partNumber: number; offset: number; size: number },
    signal: AbortSignal
  ): Promise<void> {
    const blob = file.slice(chunk.offset, chunk.offset + chunk.size)
    
    const result = await client.uploadPart(
      task.objectKey,
      task.uploadId,
      chunk.partNumber,
      blob
    )

    // 检查是否被中止
    if (signal.aborted) {
      throw new Error('上传被中止')
    }

    // 更新任务信息
    const chunkInfo: ChunkInfo = {
      partNumber: chunk.partNumber,
      etag: result.etag,
      size: chunk.size,
      offset: chunk.offset
    }

    task.uploadedParts.push(chunkInfo)
    task.completedParts = task.uploadedParts.length
    task.progress = Math.round((task.completedParts / task.totalParts) * 100)
    task.lastUpdateTime = Date.now()
    
    this.saveTaskToStorage(task)
  }

  // 暂停上传
  async pauseUpload(taskId: string): Promise<boolean> {
    const task = this.tasks.get(taskId)
    if (!task) {
      return false
    }

    // 中止当前上传
    const abortController = this.activeUploads.get(taskId)
    if (abortController) {
      abortController.abort()
      this.activeUploads.delete(taskId)
    }

    // 更新任务状态
    task.status = 'paused'
    task.lastUpdateTime = Date.now()
    this.saveTaskToStorage(task)

    return true
  }

  // 取消上传
  async cancelUpload(taskId: string): Promise<boolean> {
    const task = this.tasks.get(taskId)
    if (!task) {
      return false
    }

    try {
      // 中止当前上传
      const abortController = this.activeUploads.get(taskId)
      if (abortController) {
        abortController.abort()
        this.activeUploads.delete(taskId)
      }

      // 如果有uploadId，中止分片上传
      if (task.uploadId) {
        const client = this.createOSSClient()
        await client.abortMultipartUpload(task.objectKey, task.uploadId)
      }

      // 删除任务
      this.tasks.delete(taskId)
      this.removeTaskFromStorage(taskId)

      return true
    } catch (error) {
      console.error('取消上传失败:', error)
      return false
    }
  }

  // 获取任务信息
  getTask(taskId: string): UploadTask | undefined {
    return this.tasks.get(taskId)
  }

  // 获取所有任务
  getAllTasks(): UploadTask[] {
    return Array.from(this.tasks.values())
  }

  // 清理已完成的任务
  clearCompletedTasks(): void {
    const completedTasks = Array.from(this.tasks.values())
      .filter(task => task.status === 'completed')
    
    completedTasks.forEach(task => {
      this.tasks.delete(task.id)
      this.removeTaskFromStorage(task.id)
    })
  }

  // 清理所有任务
  clearAllTasks(): void {
    this.tasks.clear()
    
    // 清理本地存储
    const keys = Object.keys(localStorage).filter(key => 
      key.startsWith(this.config.storageKeyPrefix)
    )
    keys.forEach(key => localStorage.removeItem(key))
  }
}

// 创建全局实例
export const resumeUploadManager = new ResumeUploadManager()
